/**
*		@file Modifies.cpp
*		@brief Modifies class
*
*		@author Zhou Nan
*
*		@date 1/25/2012
*/

#include "Modifies.h"

vector<ModifiesEntry*>	Modifies::vp_modifies_entries_;
vector<VarSet>	Modifies::modifies_stmt_table_;
vector<StmtSet>	Modifies::modifies_stmt_table_t_;

vector<VarSet>	Modifies::modifies_proc_table_;
vector<ProcSet>	Modifies::modifies_proc_table_t_;

StmtSet			Modifies::modifies_has_s0_;
ProcSet			Modifies::modifies_has_p0_;
VarSet			Modifies::modifies_has_0v_;
bool			Modifies::modifies_has_00_;

void Modifies::SetModifiesA(StmtNum stmt_num_assign, VarIdx var_idx)
{
	ModifiesEntry* p_modifies_entry_temp = new ModifiesEntry;
	p_modifies_entry_temp->stmt_num=stmt_num_assign;
	p_modifies_entry_temp->var_idx=var_idx;

	vp_modifies_entries_.push_back(p_modifies_entry_temp);
}

void Modifies::RebuildModifies()
{
	// dynamic memory allocation for modifies_stmt_table_
	modifies_stmt_table_.resize(StmtTable::GetSize());
	for( int i = 0; i < StmtTable::GetSize(); i++ )
	{
		modifies_stmt_table_[i].resize(VarTable::GetSize());
	}

	// dynamic memory allocation for modifies_proc_table_
	modifies_proc_table_.resize(ProcTable::GetSize());
	for( int i = 0; i < ProcTable::GetSize(); i++ )
	{
		modifies_proc_table_[i].resize(VarTable::GetSize());
	}

	// copy data from linked list to array
	for(unsigned int i = 0; i < vp_modifies_entries_.size(); i++ )
	{
		modifies_stmt_table_[vp_modifies_entries_[i]->stmt_num-1][vp_modifies_entries_[i]->var_idx-1] = true;
	}

	// free memory of linked list
	vp_modifies_entries_.clear();

	modifies_has_s0_.resize(StmtTable::GetSize());
	modifies_has_p0_.resize(ProcTable::GetSize());
	modifies_has_0v_.resize(VarTable::GetSize());
	modifies_has_00_=false;
	return;
}

void Modifies::TransposeModifies()
{
	modifies_stmt_table_t_.resize(VarTable::GetSize());
	modifies_proc_table_t_.resize(VarTable::GetSize());
	for( int i = 0; i < VarTable::GetSize(); i++ )
	{
		modifies_stmt_table_t_[i].resize(StmtTable::GetSize());
		modifies_proc_table_t_[i].resize(ProcTable::GetSize());
	}

	for( int i = 0; i < VarTable::GetSize(); i++ )
	{
		for( int j = 0; j < StmtTable::GetSize(); j++ )
			modifies_stmt_table_t_[i][j] = modifies_stmt_table_[j][i];
		for( int j = 0; j < ProcTable::GetSize(); j++ )
			modifies_proc_table_t_[i][j] = modifies_proc_table_[j][i];
	}
}

void Modifies::CompleteModifes()
{
	for( int i = 0; i < StmtTable::GetSize(); i++ )		modifies_has_s0_[i] = IsAny<VarSet>(modifies_stmt_table_[i]);
	for( int i = 0; i < ProcTable::GetSize(); i++ )		modifies_has_p0_[i] = IsAny<VarSet>(modifies_proc_table_[i]);
	for( int i = 0; i < VarTable::GetSize(); i++ )		modifies_has_0v_[i] = IsAny<ProcSet>(modifies_proc_table_t_[i]);
	modifies_has_00_ = IsAny<VarSet>(modifies_has_0v_);
	return;
}

void Modifies::SetModifiesS(StmtNum stmt_num, VarSet var_set)
{
	modifies_stmt_table_[stmt_num-1] = var_set;
}

void Modifies::SetModifiesP(ProcIdx proc_idx, VarSet var_set)
{
	modifies_proc_table_[proc_idx-1] = var_set;
}

VarSet& Modifies::GetModifiesS(StmtNum stmt_num)
{
	return modifies_stmt_table_[stmt_num-1];
}

VarSet& Modifies::GetModifiesP(ProcIdx proc_idx)
{
	return modifies_proc_table_[proc_idx-1];
}

StmtSet& Modifies::GetModifiesByS(VarIdx var_idx)
{
	return modifies_stmt_table_t_[var_idx-1];
}

ProcSet& Modifies::GetModifiesByP(VarIdx var_idx)
{
	return modifies_proc_table_t_[var_idx-1];
}

bool Modifies::IsModifiesS(StmtNum stmt_num, VarIdx var_idx)
{
	if( stmt_num > StmtTable::GetSize() )
		return false;
	if( stmt_num == 0 )
	{
		if( var_idx == 0 )
			return modifies_has_00_;
		else
			return modifies_has_0v_[var_idx - 1];
	}
	else
	{
		if( var_idx == 0 )
			return modifies_has_s0_[stmt_num - 1];
		else
			return modifies_stmt_table_[stmt_num-1][var_idx-1];
	}
}

bool Modifies::IsModifiesP(ProcIdx proc_idx, VarIdx var_idx)
{
	if( proc_idx == 0 )
	{
		if( var_idx == 0 )
			return modifies_has_00_;
		else
			return modifies_has_0v_[var_idx - 1];
	}
	else
	{
		if( var_idx == 0 )
			return modifies_has_p0_[proc_idx - 1];
		else
			return modifies_proc_table_[proc_idx-1][var_idx-1];
	}
}

string Modifies::ToString()
{
	stringstream ss_result;
	
	ss_result << "Modifies : " << modifies_has_00_ << "\nModifies stmt:\n";
	for( int i = 0; i < StmtTable::GetSize(); i++ )
	{
		ss_result << (i+1)  << " [" << modifies_has_s0_[i] << "] : ";
		for( int j = 0; j < VarTable::GetSize(); j++ )
			if( modifies_stmt_table_[i][j] )
				ss_result << VarTable::GetVarName(j+1) <<" ";
		ss_result << "\n";
	}

	ss_result << "Modifies proc:\n";
	for( int i = 0; i < ProcTable::GetSize(); i++ )
	{
		ss_result << (i+1)  << " [" << modifies_has_p0_[i] << "] : ";
		for( int j = 0; j < VarTable::GetSize(); j++ )
			if( modifies_proc_table_[i][j] )
				ss_result << VarTable::GetVarName(j+1) <<" ";
		ss_result << "\n";
	}

	return ss_result.str();
}